package com.dh.spring.thread;

import com.dh.spring.thread.callable.InternalCallableTask;
import com.dh.spring.thread.callable.ThreadCallable;
import com.dh.spring.thread.runnable.InternalRunnableTask;
import com.dh.spring.thread.runnable.ThreadRunnable;
import com.dh.spring.util.LocalTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池阻塞队列接口实现类
 *
 *  该线程工厂用于创建线程执行线程池内部任务逻辑，负责从任务阻塞队列中不断获取任务执行
 * */
public class CustomDefaultThreadFactory implements CustomThreadFactory {
    private static final Logger logger = LoggerFactory.getLogger(CustomDefaultThreadFactory.class);
    //TODO 活跃的线程数
    private static AtomicInteger activeRunnableSize = new AtomicInteger(0),
        activeCallableSize = new AtomicInteger(0);
    //TODO 记录线程池内部线程标记，用于排查哪个线程阻塞
    private int index = 0;
    //TODO 封装线程和执行单元的队列
    private static Queue<Object> queue = new ArrayDeque<>();
    private static Object lock = new Object();
    private static volatile CustomThreadFactory customThreadFactory = null;

    public static CustomThreadFactory getInstance() {
        if(null == customThreadFactory) {
            synchronized (CustomDefaultThreadFactory.class) {
                if(null == customThreadFactory) {
                    customThreadFactory = new CustomDefaultThreadFactory();
                }
            }
        }

        return customThreadFactory;
    }

    @Override
    public void execute(CustomThreadPool customThreadPool, CustomTaskBlockQueue customTaskBlockQueue, Class cls) {
        this.buildAndCreateThread(customThreadPool, customTaskBlockQueue, cls);
    }

    private void buildAndCreateThread(CustomThreadPool customThreadPool, CustomTaskBlockQueue customTaskBlockQueue, Class cls) {
        synchronized (lock) {
            if (null == cls) { //TODO 默认创建Runnable线程
                //TODO 创建线程池线程执行单元任务
                InternalRunnableTask internalRunnableTask = new InternalRunnableTask(customThreadPool, customTaskBlockQueue);
                //TODO 创建线程
                Thread thread = this.createThread(internalRunnableTask);
                //TODO 封装线程执行单元和线程
                queue.add(new ThreadRunnable(internalRunnableTask, thread));

                //TODO 线程执行启动
                thread.start();

                //TODO CAS原子进行更新
                int value = activeRunnableSize.get();
                activeCallableSize.compareAndSet(value, value + 1);
            } else {
                //TODO InternalCallableTask将会返回Callable执行单元返回的结果
                InternalCallableTask internalCallableTask = new InternalCallableTask(customThreadPool, customTaskBlockQueue);
                FutureTask<Callable> futureTask = new FutureTask<>(internalCallableTask);
                ((CustomDefaultThreadPool) customThreadPool).getList().add(futureTask);
                queue.add(new ThreadCallable(internalCallableTask, null));

                int value = activeCallableSize.get();
                activeCallableSize.compareAndSet(value, value + 1);
            }
        }

        List<FutureTask<Callable>> internalCallTaskList = ((CustomDefaultThreadPool) customThreadPool).getList();
        if(!((CustomDefaultThreadPool) customThreadPool).getList().isEmpty()) {
            for(FutureTask futureTask : internalCallTaskList) {
                if(null != futureTask) {
                    futureTask.run();
                }
            }
        }
    }

    @Override
    public Thread createThread(Object object) {
        if(object instanceof Runnable) {
            return new Thread(((Runnable) object), "线程池内部执行线程(Runnable线程)索引 " + (index++));
        } else {
            FutureTask<Object> futureTask = new FutureTask<>((Callable) object);
            return new Thread(futureTask, "线程池内部执行线程(Callable线程)索引 " + (index++));
        }
    }

    @Override
    public int getActiveThreadSize(CustomThreadPool customThreadPool) {
        synchronized (lock) {
            if (((CustomDefaultThreadPool<Object>) customThreadPool).getThreadPoolName().equals("Runnable维护线程")) {
                return activeRunnableSize.get();
            }

            if (((CustomDefaultThreadPool<Object>) customThreadPool).getThreadPoolName().equals("Callable维护线程")) {
                return activeCallableSize.get();
            }
        }

        return -1;
    }

    @Override
    public void removeThread(CustomThreadPool customThreadPool) {
        //TODO 线程池处于开启且活跃线程个数大于0，即可移除线程
        if(!customThreadPool.isShutdown() && this.getActiveThreadSize(customThreadPool) > 0) {
            Object object = this.queue.remove();
            if(object instanceof ThreadRunnable) {
                //TODO 终止线程内部任务执行
                ((ThreadRunnable) object).getInternalRunnableTask().stop();
                //TODO 终止线程
                ((ThreadRunnable) object).getThread().interrupt();

                int value = activeRunnableSize.get();
                activeRunnableSize.compareAndSet(value, value - 1);
                return;
            }
            if(object instanceof ThreadCallable){
                //TODO 终止线程内部任务执行
                ((ThreadCallable) object).getInternalCallableTask().stop();
                //TODO 终止线程
                //((ThreadCallable) object).getThread().interrupt();

                int value = activeCallableSize.get();
                activeCallableSize.compareAndSet(value, value - 1);
                return;
            }
        }

        logger.info("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ]" + " 当前线程池已处于停止状态或活跃线程个数为0，无法移除线程......");
    }

    public static Queue<Object> getQueue() {
        return queue;
    }

    //TODO 释放对应活跃线程个数
    public static void releaseThread(CustomThreadPool customThreadPool) {
        if(customThreadPool.getActiveThreadSize() != 0) {
            synchronized (lock) {
                if (((CustomDefaultThreadPool<Object>) customThreadPool).getThreadPoolName().equals("Runnable维护线程")) {
                    int value = activeRunnableSize.get();
                    activeRunnableSize.compareAndSet(value, value - 1);
                }

                if (((CustomDefaultThreadPool<Object>) customThreadPool).getThreadPoolName().equals("Callable维护线程")) {
                    int value = activeCallableSize.get();
                    activeCallableSize.compareAndSet(value, value - 1);
                }
            }
        }
    }
}
